package com.shiwaixiangcun.monitor.config;

import com.alibaba.fastjson.serializer.ObjectSerializer;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializeWriter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.spring.FastJsonJsonView;
import com.shiwaixiangcun.core.web.bind.method.annotation.MonkeyDtoMethodArgumentResolver;
import com.shiwaixiangcun.core.web.bind.method.annotation.PageableMethodArgumentResolver;
import com.shiwaixiangcun.core.web.bind.method.annotation.SearchableMethodArgumentResolver;
import com.shiwaixiangcun.core.web.filters.MonkeyCharacterEncodingFilter;
import com.shiwaixiangcun.core.web.view.json.MsFastJsonView;
import com.shiwaixiangcun.core.web.view.pdf.AppPdfView;
import com.shiwaixiangcun.monitor.dto.WorkHandler;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;

import java.math.BigInteger;
import java.util.*;

@Configuration
@ComponentScan(
        basePackages = {"com.shiwaixiangcun.monitor.controller","com.shiwaixiangcun.baidu"},
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class, ControllerAdvice.class})}
)
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new PageableMethodArgumentResolver());
        argumentResolvers.add(new MonkeyDtoMethodArgumentResolver());
        argumentResolvers.add(new SearchableMethodArgumentResolver());
    }

    /**
     * 内容协商管理器
     * 1、首先检查路径扩展名（如my.pdf）；2、其次检查Parameter（如my?format=pdf）；3、检查Accept Header
     */
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        // 扩展名至mimeType的映射,即 /user.json => application/json
        configurer.favorPathExtension(true);
        //用于开启 /userinfo/123?format=json 的支持
        configurer.favorParameter(true);
        // <!-- 是否忽略Accept Header -->
        configurer.ignoreAcceptHeader(true);
        //<!--扩展名到MIME的映射；favorPathExtension, favorParameter是true时起作用  -->
        Map<String, MediaType> mediaTypes = new HashMap<>();
        mediaTypes.put("json", MediaType.APPLICATION_JSON_UTF8);
//        mediaTypes.put("xml", MediaType.APPLICATION_XML);
        mediaTypes.put("pdf", MediaType.APPLICATION_PDF);
        mediaTypes.put("htm", MediaType.TEXT_HTML);
        mediaTypes.put("xls", MediaType.valueOf("application/vnd.ms-excel"));
        configurer.mediaTypes(mediaTypes);
        configurer.defaultContentType(MediaType.TEXT_HTML);
    }

    /**
     * 内容协商视图解析器；根据客户端的不同的请求决定不同的 view进行响应, 如 /blog/1.json /blog/1.xml
     * 会自动根据解析的contentType来决定使用哪个视图解析器（默认使用整个web应用中的viewResolver）
     *
     * @return
     */
    @Bean
    public ContentNegotiatingViewResolver viewResolver(ContentNegotiationManager contentNegotiationManager) {
        ContentNegotiatingViewResolver viewResolver = new ContentNegotiatingViewResolver();
        viewResolver.setOrder(0);
        viewResolver.setContentNegotiationManager(contentNegotiationManager);
        //<!-- 默认视图 放在解析链最后 -->
        //viewResolver.setDefaultViews(Collections.singletonList(fastJsonJsonView()));
        viewResolver.setDefaultViews(Arrays.asList(pdfView(), fastJsonJsonView()));
        return viewResolver;
    }

    @Bean
    public FastJsonJsonView fastJsonJsonView() {
        //Long 类型直接转换为字符串返回，避免截断
        ObjectSerializer serializer = longToStringSerializer();
        SerializeConfig serializeConfig = SerializeConfig.getGlobalInstance();
        serializeConfig.put(Long.class, serializer);
        serializeConfig.put(BigInteger.class, serializer);
        serializeConfig.put(Long.TYPE, serializer);


        MsFastJsonView jsonView = new MsFastJsonView();
        jsonView.setFeatures(SerializerFeature.WriteMapNullValue);
        jsonView.setExtractValueFromSingleKeyModel(true);
        return jsonView;
    }

    private ObjectSerializer longToStringSerializer() {
        return (serializer, object, fieldName, fieldType, features) -> {
            SerializeWriter out = serializer.getWriter();
            out.writeString(Objects.toString(object, ""));
        };
    }


    @Bean
    public AppPdfView pdfView() {
        return new AppPdfView();
    }

    @Bean
    public MonkeyCharacterEncodingFilter monkeyCharacterEncodingFilter() {
        return new MonkeyCharacterEncodingFilter();
    }

    @Bean
    public WorkHandler workHandler() {
        return new WorkHandler();
    }

}
